home *** CD-ROM | disk | FTP | other *** search
/ Languguage OS 2 / Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO / gnu / gas_251.zip / bin_251 / binutils / nlmheader.y < prev    next >
Text File  |  1994-08-01  |  21KB  |  980 lines

  1. %{/* nlmheader.y - parse NLM header specification keywords.
  2.      Copyright (C) 1993 Free Software Foundation, Inc.
  3.  
  4. This file is part of GNU Binutils.
  5.  
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2 of the License, or
  9. (at your option) any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. /* Written by Ian Lance Taylor <ian@cygnus.com>.
  21.  
  22.    This bison file parses the commands recognized by the NetWare NLM
  23.    linker, except for lists of object files.  It stores the
  24.    information in global variables.
  25.  
  26.    This implementation is based on the description in the NetWare Tool
  27.    Maker Specification manual, edition 1.0.  */
  28.  
  29. #include <ansidecl.h>
  30. #include <stdio.h>
  31. #include <ctype.h>
  32. #include "bfd.h"
  33. #include "sysdep.h"
  34. #include "bucomm.h"
  35. #include "nlm/common.h"
  36. #include "nlm/internal.h"
  37. #include "nlmconv.h"
  38.  
  39. /* Information is stored in the structures pointed to by these
  40.    variables.  */
  41.  
  42. Nlm_Internal_Fixed_Header *fixed_hdr;
  43. Nlm_Internal_Variable_Header *var_hdr;
  44. Nlm_Internal_Version_Header *version_hdr;
  45. Nlm_Internal_Copyright_Header *copyright_hdr;
  46. Nlm_Internal_Extended_Header *extended_hdr;
  47.  
  48. /* Procedure named by CHECK.  */
  49. char *check_procedure;
  50. /* File named by CUSTOM.  */
  51. char *custom_file;
  52. /* Whether to generate debugging information (DEBUG).  */
  53. boolean debug_info;
  54. /* Procedure named by EXIT.  */
  55. char *exit_procedure;
  56. /* Exported symbols (EXPORT).  */
  57. struct string_list *export_symbols;
  58. /* List of files from INPUT.  */
  59. struct string_list *input_files;
  60. /* Map file name (MAP, FULLMAP).  */
  61. char *map_file;
  62. /* Whether a full map has been requested (FULLMAP).  */
  63. boolean full_map;
  64. /* File named by HELP.  */
  65. char *help_file;
  66. /* Imported symbols (IMPORT).  */
  67. struct string_list *import_symbols;
  68. /* File named by MESSAGES.  */
  69. char *message_file;
  70. /* Autoload module list (MODULE).  */
  71. struct string_list *modules;
  72. /* File named by OUTPUT.  */
  73. char *output_file;
  74. /* File named by SHARELIB.  */
  75. char *sharelib_file;
  76. /* Start procedure name (START).  */
  77. char *start_procedure;
  78. /* VERBOSE.  */
  79. boolean verbose;
  80. /* RPC description file (XDCDATA).  */
  81. char *rpc_file;
  82.  
  83. /* The number of serious errors that have occurred.  */
  84. int parse_errors;
  85.  
  86. /* The current symbol prefix when reading a list of import or export
  87.    symbols.  */
  88. static char *symbol_prefix;
  89.  
  90. /* Parser error message handler.  */
  91. #define yyerror(msg) nlmheader_error (msg);
  92.  
  93. /* Local functions.  */
  94. static int yylex PARAMS ((void));
  95. static void nlmlex_file_push PARAMS ((const char *));
  96. static boolean nlmlex_file_open PARAMS ((const char *));
  97. static int nlmlex_buf_init PARAMS ((void));
  98. static char nlmlex_buf_add PARAMS ((int));
  99. static long nlmlex_get_number PARAMS ((const char *));
  100. static void nlmheader_identify PARAMS ((void));
  101. static void nlmheader_warn PARAMS ((const char *, int));
  102. static void nlmheader_error PARAMS ((const char *));
  103. static struct string_list * string_list_cons PARAMS ((char *,
  104.                               struct string_list *));
  105. static struct string_list * string_list_append PARAMS ((struct string_list *,
  106.                             struct string_list *));
  107. static struct string_list * string_list_append1 PARAMS ((struct string_list *,
  108.                              char *));
  109. static char *xstrdup PARAMS ((const char *));
  110.  
  111. %}
  112.  
  113. %union
  114. {
  115.   char *string;
  116.   struct string_list *list;
  117. };
  118.  
  119. /* The reserved words.  */
  120.  
  121. %token CHECK CODESTART COPYRIGHT CUSTOM DATE DEBUG DESCRIPTION EXIT
  122. %token EXPORT FLAG_ON FLAG_OFF FULLMAP HELP IMPORT INPUT MAP MESSAGES
  123. %token MODULE MULTIPLE OS_DOMAIN OUTPUT PSEUDOPREEMPTION REENTRANT
  124. %token SCREENNAME SHARELIB STACK START SYNCHRONIZE
  125. %token THREADNAME TYPE VERBOSE VERSION XDCDATA
  126.  
  127. /* Arguments.  */
  128.  
  129. %token <string> STRING
  130. %token <string> QUOTED_STRING
  131.  
  132. /* Typed non-terminals.  */
  133. %type <list> symbol_list_opt symbol_list string_list
  134. %type <string> symbol
  135.  
  136. %%
  137.  
  138. /* Keywords must start in the leftmost column of the file.  Arguments
  139.    may appear anywhere else.  The lexer uses this to determine what
  140.    token to return, so we don't have to worry about it here.  */
  141.  
  142. /* The entire file is just a list of commands.  */
  143.  
  144. file:    
  145.       commands
  146.     ;
  147.  
  148. /* A possibly empty list of commands.  */
  149.  
  150. commands:
  151.       /* May be empty.  */
  152.     | command commands
  153.     ;
  154.  
  155. /* A single command.  There is where most of the work takes place.  */
  156.  
  157. command:
  158.       CHECK STRING
  159.       {
  160.         check_procedure = $2;
  161.       }
  162.     | CODESTART STRING
  163.       {
  164.         nlmheader_warn ("CODESTART is not implemented; sorry", -1);
  165.         free ($2);
  166.       }
  167.     | COPYRIGHT QUOTED_STRING
  168.       {
  169.         int len;
  170.  
  171.         strncpy (copyright_hdr->stamp, "CoPyRiGhT=", 10);
  172.         len = strlen ($2);
  173.         if (len >= NLM_MAX_COPYRIGHT_MESSAGE_LENGTH)
  174.           {
  175.         nlmheader_warn ("copyright string is too long",
  176.                 NLM_MAX_COPYRIGHT_MESSAGE_LENGTH - 1);
  177.         len = NLM_MAX_COPYRIGHT_MESSAGE_LENGTH - 1;
  178.           }
  179.         copyright_hdr->copyrightMessageLength = len;
  180.         strncpy (copyright_hdr->copyrightMessage, $2, len);
  181.         copyright_hdr->copyrightMessage[len] = '\0';
  182.         free ($2);
  183.       }
  184.     | CUSTOM STRING
  185.       {
  186.         custom_file = $2;
  187.       }
  188.     | DATE STRING STRING STRING
  189.       {
  190.         /* We don't set the version stamp here, because we use the
  191.            version stamp to detect whether the required VERSION
  192.            keyword was given.  */
  193.         version_hdr->month = nlmlex_get_number ($2);
  194.         version_hdr->day = nlmlex_get_number ($3);
  195.         version_hdr->year = nlmlex_get_number ($4);
  196.         free ($2);
  197.         free ($3);
  198.         free ($4);
  199.         if (version_hdr->month < 1 || version_hdr->month > 12)
  200.           nlmheader_warn ("illegal month", -1);
  201.         if (version_hdr->day < 1 || version_hdr->day > 31)
  202.           nlmheader_warn ("illegal day", -1);
  203.         if (version_hdr->year < 1900 || version_hdr->year > 3000)
  204.           nlmheader_warn ("illegal year", -1);
  205.       }
  206.     | DEBUG
  207.       {
  208.         debug_info = true;
  209.       }
  210.     | DESCRIPTION QUOTED_STRING
  211.       {
  212.         int len;
  213.  
  214.         len = strlen ($2);
  215.         if (len > NLM_MAX_DESCRIPTION_LENGTH)
  216.           {
  217.         nlmheader_warn ("description string is too long",
  218.                 NLM_MAX_DESCRIPTION_LENGTH);
  219.         len = NLM_MAX_DESCRIPTION_LENGTH;
  220.           }
  221.         var_hdr->descriptionLength = len;
  222.         strncpy (var_hdr->descriptionText, $2, len);
  223.         var_hdr->descriptionText[len] = '\0';
  224.         free ($2);
  225.       }
  226.     | EXIT STRING
  227.       {
  228.         exit_procedure = $2;
  229.       }
  230.     | EXPORT
  231.       {
  232.         symbol_prefix = NULL;
  233.       }
  234.       symbol_list_opt
  235.       {
  236.         export_symbols = string_list_append (export_symbols, $3);
  237.       }
  238.     | FLAG_ON STRING
  239.       {
  240.         fixed_hdr->flags |= nlmlex_get_number ($2);
  241.         free ($2);
  242.       }
  243.     | FLAG_OFF STRING
  244.       {
  245.         fixed_hdr->flags &=~ nlmlex_get_number ($2);
  246.         free ($2);
  247.       }
  248.     | FULLMAP
  249.       {
  250.         map_file = "";
  251.         full_map = true;
  252.       }
  253.     | FULLMAP STRING
  254.       {
  255.         map_file = $2;
  256.         full_map = true;
  257.       }
  258.     | HELP STRING
  259.       {
  260.         help_file = $2;
  261.       }
  262.     | IMPORT
  263.       {
  264.         symbol_prefix = NULL;
  265.       }
  266.       symbol_list_opt
  267.       {
  268.         import_symbols = string_list_append (import_symbols, $3);
  269.       }
  270.     | INPUT string_list
  271.       {
  272.         input_files = string_list_append (input_files, $2);
  273.       }
  274.     | MAP
  275.       {
  276.         map_file = "";
  277.       }
  278.     | MAP STRING
  279.       {
  280.         map_file = $2;
  281.       }
  282.     | MESSAGES STRING
  283.       {
  284.         message_file = $2;
  285.       }
  286.     | MODULE string_list
  287.       {
  288.         modules = string_list_append (modules, $2);
  289.       }
  290.     | MULTIPLE
  291.       {
  292.         fixed_hdr->flags |= 0x2;
  293.       }
  294.     | OS_DOMAIN
  295.       {
  296.         fixed_hdr->flags |= 0x10;
  297.       }
  298.     | OUTPUT STRING
  299.       {
  300.         if (output_file == NULL)
  301.           output_file = $2;
  302.         else
  303.           nlmheader_warn ("ignoring duplicate OUTPUT statement", -1);
  304.       }
  305.     | PSEUDOPREEMPTION
  306.       {
  307.         fixed_hdr->flags |= 0x8;
  308.       }
  309.     | REENTRANT
  310.       {
  311.         fixed_hdr->flags |= 0x1;
  312.       }
  313.     | SCREENNAME QUOTED_STRING
  314.       {
  315.         int len;
  316.  
  317.         len = strlen ($2);
  318.         if (len >= NLM_MAX_SCREEN_NAME_LENGTH)
  319.           {
  320.         nlmheader_warn ("screen name is too long",
  321.                 NLM_MAX_SCREEN_NAME_LENGTH);
  322.         len = NLM_MAX_SCREEN_NAME_LENGTH;
  323.           }
  324.         var_hdr->screenNameLength = len;
  325.         strncpy (var_hdr->screenName, $2, len);
  326.         var_hdr->screenName[NLM_MAX_SCREEN_NAME_LENGTH] = '\0';
  327.         free ($2);
  328.       }
  329.     | SHARELIB STRING
  330.       {
  331.         sharelib_file = $2;
  332.       }
  333.     | STACK STRING
  334.       {
  335.         var_hdr->stackSize = nlmlex_get_number ($2);
  336.         free ($2);
  337.       }
  338.     | START STRING
  339.       {
  340.         start_procedure = $2;
  341.       }
  342.     | SYNCHRONIZE
  343.       {
  344.         fixed_hdr->flags |= 0x4;
  345.       }
  346.     | THREADNAME QUOTED_STRING
  347.       {
  348.         int len;
  349.  
  350.         len = strlen ($2);
  351.         if (len >= NLM_MAX_THREAD_NAME_LENGTH)
  352.           {
  353.         nlmheader_warn ("thread name is too long",
  354.                 NLM_MAX_THREAD_NAME_LENGTH);
  355.         len = NLM_MAX_THREAD_NAME_LENGTH;
  356.           }
  357.         var_hdr->threadNameLength = len;
  358.         strncpy (var_hdr->threadName, $2, len);
  359.         var_hdr->threadName[len] = '\0';
  360.         free ($2);
  361.       }
  362.     | TYPE STRING
  363.       {
  364.         fixed_hdr->moduleType = nlmlex_get_number ($2);
  365.         free ($2);
  366.       }
  367.     | VERBOSE
  368.       {
  369.         verbose = true;
  370.       }
  371.     | VERSION STRING STRING STRING
  372.       {
  373.         long val;
  374.  
  375.         strncpy (version_hdr->stamp, "VeRsIoN#", 8);
  376.         version_hdr->majorVersion = nlmlex_get_number ($2);
  377.         val = nlmlex_get_number ($3);
  378.         if (val < 0 || val > 99)
  379.           nlmheader_warn ("illegal minor version number (must be between 0 and 99)",
  380.                   -1);
  381.         else
  382.           version_hdr->minorVersion = val;
  383.         val = nlmlex_get_number ($4);
  384.         if (val < 0)
  385.           nlmheader_warn ("illegal revision number (must be between 0 and 26)",
  386.                   -1);
  387.         else if (val > 26)
  388.           version_hdr->revision = 0;
  389.         else
  390.           version_hdr->revision = val;
  391.         free ($2);
  392.         free ($3);
  393.         free ($4);
  394.       }
  395.     | VERSION STRING STRING
  396.       {
  397.         long val;
  398.  
  399.         strncpy (version_hdr->stamp, "VeRsIoN#", 8);
  400.         version_hdr->majorVersion = nlmlex_get_number ($2);
  401.         val = nlmlex_get_number ($3);
  402.         if (val < 0 || val > 99)
  403.           nlmheader_warn ("illegal minor version number (must be between 0 and 99)",
  404.                   -1);
  405.         else
  406.           version_hdr->minorVersion = val;
  407.         version_hdr->revision = 0;
  408.         free ($2);
  409.         free ($3);
  410.       }
  411.     | XDCDATA STRING
  412.       {
  413.         rpc_file = $2;
  414.       }
  415.     ;
  416.  
  417. /* A possibly empty list of symbols.  */
  418.  
  419. symbol_list_opt:
  420.       /* Empty.  */
  421.       {
  422.         $$ = NULL;
  423.       }
  424.     | symbol_list
  425.       {
  426.         $$ = $1;
  427.       }
  428.     ;
  429.  
  430. /* A list of symbols in an import or export list.  Prefixes may appear
  431.    in parentheses.  We need to use left recursion here to avoid
  432.    building up a large import list on the parser stack.  */
  433.  
  434. symbol_list:
  435.       symbol
  436.       {
  437.         $$ = string_list_cons ($1, NULL);
  438.       }
  439.     | symbol_prefix
  440.       {
  441.         $$ = NULL;
  442.       }
  443.     | symbol_list symbol
  444.       {
  445.         $$ = string_list_append1 ($1, $2);
  446.       }
  447.     | symbol_list symbol_prefix
  448.       {
  449.         $$ = $1;
  450.       }
  451.     ;
  452.  
  453. /* A prefix for subsequent symbols.  */
  454.  
  455. symbol_prefix:
  456.       '(' STRING ')'
  457.       {
  458.         if (symbol_prefix != NULL)
  459.           free (symbol_prefix);
  460.         symbol_prefix = $2;
  461.       }
  462.     ;
  463.  
  464. /* A single symbol.  */
  465.  
  466. symbol:
  467.       STRING
  468.       {
  469.         if (symbol_prefix == NULL)
  470.           $$ = $1;
  471.         else
  472.           {
  473.         $$ = xmalloc (strlen (symbol_prefix) + strlen ($1) + 2);
  474.         sprintf ($$, "%s@%s", symbol_prefix, $1);
  475.         free ($1);
  476.           }
  477.       }
  478.     ;
  479.  
  480. /* A list of strings.  */
  481.  
  482. string_list:
  483.       /* May be empty.  */
  484.       {
  485.         $$ = NULL;
  486.       }
  487.     | STRING string_list
  488.       {
  489.         $$ = string_list_cons ($1, $2);
  490.       }
  491.     ;
  492.  
  493. %%
  494.  
  495. /* If strerror is just a macro, we want to use the one from libiberty
  496.    since it will handle undefined values.  */
  497. #undef strerror
  498. extern char *strerror ();
  499.  
  500. /* The lexer is simple, too simple for flex.  Keywords are only
  501.    recognized at the start of lines.  Everything else must be an
  502.    argument.  A comma is treated as whitespace.  */
  503.  
  504. /* The states the lexer can be in.  */
  505.  
  506. enum lex_state
  507. {
  508.   /* At the beginning of a line.  */
  509.   BEGINNING_OF_LINE,
  510.   /* In the middle of a line.  */
  511.   IN_LINE
  512. };
  513.  
  514. /* We need to keep a stack of files to handle file inclusion.  */
  515.  
  516. struct input
  517. {
  518.   /* The file to read from.  */
  519.   FILE *file;
  520.   /* The name of the file.  */
  521.   char *name;
  522.   /* The current line number.  */
  523.   int lineno;
  524.   /* The current state.  */
  525.   enum lex_state state;
  526.   /* The next file on the stack.  */
  527.   struct input *next;
  528. };
  529.  
  530. /* The current input file.  */
  531.  
  532. static struct input current;
  533.  
  534. /* The character which introduces comments.  */
  535. #define COMMENT_CHAR '#'
  536.  
  537. /* Start the lexer going on the main input file.  */
  538.  
  539. boolean
  540. nlmlex_file (name)
  541.      const char *name;
  542. {
  543.   current.next = NULL;
  544.   return nlmlex_file_open (name);
  545. }
  546.  
  547. /* Start the lexer going on a subsidiary input file.  */
  548.  
  549. static void
  550. nlmlex_file_push (name)
  551.      const char *name;
  552. {
  553.   struct input *push;
  554.  
  555.   push = (struct input *) xmalloc (sizeof (struct input));
  556.   *push = current;
  557.   if (nlmlex_file_open (name))
  558.     current.next = push;
  559.   else
  560.     {
  561.       current = *push;
  562.       free (push);
  563.     }
  564. }
  565.  
  566. /* Start lexing from a file.  */
  567.  
  568. static boolean
  569. nlmlex_file_open (name)
  570.      const char *name;
  571. {
  572.   current.file = fopen (name, "r");
  573.   if (current.file == NULL)
  574.     {
  575.       fprintf (stderr, "%s:%s: %s\n", program_name, name, strerror (errno));
  576.       ++parse_errors;
  577.       return false;
  578.     }
  579.   current.name = xstrdup (name);
  580.   current.lineno = 1;
  581.   current.state = BEGINNING_OF_LINE;
  582.   return true;
  583. }
  584.  
  585. /* Table used to turn keywords into tokens.  */
  586.  
  587. struct keyword_tokens_struct
  588. {
  589.   const char *keyword;
  590.   int token;
  591. };
  592.  
  593. struct keyword_tokens_struct keyword_tokens[] =
  594. {
  595.   { "CHECK", CHECK },
  596.   { "CODESTART", CODESTART },
  597.   { "COPYRIGHT", COPYRIGHT },
  598.   { "CUSTOM", CUSTOM },
  599.   { "DATE", DATE },
  600.   { "DEBUG", DEBUG },
  601.   { "DESCRIPTION", DESCRIPTION },
  602.   { "EXIT", EXIT },
  603.   { "EXPORT", EXPORT },
  604.   { "FLAG_ON", FLAG_ON },
  605.   { "FLAG_OFF", FLAG_OFF },
  606.   { "FULLMAP", FULLMAP },
  607.   { "HELP", HELP },
  608.   { "IMPORT", IMPORT },
  609.   { "INPUT", INPUT },
  610.   { "MAP", MAP },
  611.   { "MESSAGES", MESSAGES },
  612.   { "MODULE", MODULE },
  613.   { "MULTIPLE", MULTIPLE },
  614.   { "OS_DOMAIN", OS_DOMAIN },
  615.   { "OUTPUT", OUTPUT },
  616.   { "PSEUDOPREEMPTION", PSEUDOPREEMPTION },
  617.   { "REENTRANT", REENTRANT },
  618.   { "SCREENNAME", SCREENNAME },
  619.   { "SHARELIB", SHARELIB },
  620.   { "STACK", STACK },
  621.   { "STACKSIZE", STACK },
  622.   { "START", START },
  623.   { "SYNCHRONIZE", SYNCHRONIZE },
  624.   { "THREADNAME", THREADNAME },
  625.   { "TYPE", TYPE },
  626.   { "VERBOSE", VERBOSE },
  627.   { "VERSION", VERSION },
  628.   { "XDCDATA", XDCDATA }
  629. };
  630.  
  631. #define KEYWORD_COUNT (sizeof (keyword_tokens) / sizeof (keyword_tokens[0]))
  632.  
  633. /* The lexer accumulates strings in these variables.  */
  634. static char *lex_buf;
  635. static int lex_size;
  636. static int lex_pos;
  637.  
  638. /* Start accumulating strings into the buffer.  */
  639. #define BUF_INIT() \
  640.   ((void) (lex_buf != NULL ? lex_pos = 0 : nlmlex_buf_init ()))
  641.  
  642. static int
  643. nlmlex_buf_init ()
  644. {
  645.   lex_size = 10;
  646.   lex_buf = xmalloc (lex_size + 1);
  647.   lex_pos = 0;
  648.   return 0;
  649. }
  650.  
  651. /* Finish a string in the buffer.  */
  652. #define BUF_FINISH() ((void) (lex_buf[lex_pos] = '\0'))
  653.  
  654. /* Accumulate a character into the buffer.  */
  655. #define BUF_ADD(c) \
  656.   ((void) (lex_pos < lex_size \
  657.        ? lex_buf[lex_pos++] = (c) \
  658.        : nlmlex_buf_add (c)))
  659.  
  660. static char
  661. nlmlex_buf_add (c)
  662.      int c;
  663. {
  664.   if (lex_pos >= lex_size)
  665.     {
  666.       lex_size *= 2;
  667.       lex_buf = xrealloc (lex_buf, lex_size + 1);
  668.     }
  669.  
  670.   return lex_buf[lex_pos++] = c;
  671. }
  672.  
  673. /* The lexer proper.  This is called by the bison generated parsing
  674.    code.  */
  675.  
  676. static int
  677. yylex ()
  678. {
  679.   int c;
  680.  
  681. tail_recurse:
  682.  
  683.   c = getc (current.file);
  684.  
  685.   /* Commas are treated as whitespace characters.  */
  686.   while (isspace ((unsigned char) c) || c == ',')
  687.     {
  688.       current.state = IN_LINE;
  689.       if (c == '\n')
  690.     {
  691.       ++current.lineno;
  692.       current.state = BEGINNING_OF_LINE;
  693.     }
  694.       c = getc (current.file);
  695.     }
  696.  
  697.   /* At the end of the file we either pop to the previous file or
  698.      finish up.  */
  699.   if (c == EOF)
  700.     {
  701.       fclose (current.file);
  702.       free (current.name);
  703.       if (current.next == NULL)
  704.     return 0;
  705.       else
  706.     {
  707.       struct input *next;
  708.  
  709.       next = current.next;
  710.       current = *next;
  711.       free (next);
  712.       goto tail_recurse;
  713.     }
  714.     }
  715.  
  716.   /* A comment character always means to drop everything until the
  717.      next newline.  */
  718.   if (c == COMMENT_CHAR)
  719.     {
  720.       do
  721.     {
  722.       c = getc (current.file);
  723.     }
  724.       while (c != '\n');
  725.       ++current.lineno;
  726.       current.state = BEGINNING_OF_LINE;
  727.       goto tail_recurse;
  728.     }
  729.  
  730.   /* An '@' introduces an include file.  */
  731.   if (c == '@')
  732.     {
  733.       do
  734.     {
  735.       c = getc (current.file);
  736.       if (c == '\n')
  737.         ++current.lineno;
  738.     }
  739.       while (isspace ((unsigned char) c));
  740.       BUF_INIT ();
  741.       while (! isspace ((unsigned char) c) && c != EOF)
  742.     {
  743.       BUF_ADD (c);
  744.       c = getc (current.file);
  745.     }
  746.       BUF_FINISH ();
  747.  
  748.       ungetc (c, current.file);
  749.       
  750.       nlmlex_file_push (lex_buf);
  751.       goto tail_recurse;
  752.     }
  753.  
  754.   /* A non-space character at the start of a line must be the start of
  755.      a keyword.  */
  756.   if (current.state == BEGINNING_OF_LINE)
  757.     {
  758.       BUF_INIT ();
  759.       while (isalnum ((unsigned char) c) || c == '_')
  760.     {
  761.       if (islower ((unsigned char) c))
  762.         BUF_ADD (toupper ((unsigned char) c));
  763.       else
  764.         BUF_ADD (c);
  765.       c = getc (current.file);
  766.     }
  767.       BUF_FINISH ();
  768.  
  769.       if (c != EOF && ! isspace ((unsigned char) c) && c != ',')
  770.     {
  771.       nlmheader_identify ();
  772.       fprintf (stderr, "%s:%d: illegal character in keyword: %c\n",
  773.            current.name, current.lineno, c);
  774.     }
  775.       else
  776.     {
  777.       int i;
  778.  
  779.       for (i = 0; i < KEYWORD_COUNT; i++)
  780.         {
  781.           if (lex_buf[0] == keyword_tokens[i].keyword[0]
  782.           && strcmp (lex_buf, keyword_tokens[i].keyword) == 0)
  783.         {
  784.           /* Pushing back the final whitespace avoids worrying
  785.              about \n here.  */
  786.           ungetc (c, current.file);
  787.           current.state = IN_LINE;
  788.           return keyword_tokens[i].token;
  789.         }
  790.         }
  791.       
  792.       nlmheader_identify ();
  793.       fprintf (stderr, "%s:%d: unrecognized keyword: %s\n",
  794.            current.name, current.lineno, lex_buf);
  795.     }
  796.  
  797.       ++parse_errors;
  798.       /* Treat the rest of this line as a comment.  */
  799.       ungetc (COMMENT_CHAR, current.file);
  800.       goto tail_recurse;
  801.     }
  802.  
  803.   /* Parentheses just represent themselves.  */
  804.   if (c == '(' || c == ')')
  805.     return c;
  806.  
  807.   /* Handle quoted strings.  */
  808.   if (c == '"' || c == '\'')
  809.     {
  810.       int quote;
  811.       int start_lineno;
  812.  
  813.       quote = c;
  814.       start_lineno = current.lineno;
  815.  
  816.       c = getc (current.file);
  817.       BUF_INIT ();
  818.       while (c != quote && c != EOF)
  819.     {
  820.       BUF_ADD (c);
  821.       if (c == '\n')
  822.         ++current.lineno;
  823.       c = getc (current.file);
  824.     }
  825.       BUF_FINISH ();
  826.  
  827.       if (c == EOF)
  828.     {
  829.       nlmheader_identify ();
  830.       fprintf (stderr, "%s:%d: end of file in quoted string\n",
  831.            current.name, start_lineno);
  832.       ++parse_errors;
  833.     }
  834.  
  835.       /* FIXME: Possible memory leak.  */
  836.       yylval.string = xstrdup (lex_buf);
  837.       return QUOTED_STRING;
  838.     }
  839.  
  840.   /* Gather a generic argument.  */
  841.   BUF_INIT ();
  842.   while (! isspace (c)
  843.      && c != ','
  844.      && c != COMMENT_CHAR
  845.      && c != '('
  846.      && c != ')')
  847.     {
  848.       BUF_ADD (c);
  849.       c = getc (current.file);
  850.     }
  851.   BUF_FINISH ();
  852.  
  853.   ungetc (c, current.file);
  854.  
  855.   /* FIXME: Possible memory leak.  */
  856.   yylval.string = xstrdup (lex_buf);
  857.   return STRING;
  858. }
  859.  
  860. /* Get a number from a string.  */
  861.  
  862. static long
  863. nlmlex_get_number (s)
  864.      const char *s;
  865. {
  866.   long ret;
  867.   char *send;
  868.  
  869.   ret = strtol (s, &send, 10);
  870.   if (*send != '\0')
  871.     nlmheader_warn ("bad number", -1);
  872.   return ret;
  873. }
  874.  
  875. /* Prefix the nlmconv warnings with a note as to where they come from.
  876.    We don't use program_name on every warning, because then some
  877.    versions of the emacs next-error function can't recognize the line
  878.    number.  */
  879.  
  880. static void
  881. nlmheader_identify ()
  882. {
  883.   static int done;
  884.  
  885.   if (! done)
  886.     {
  887.       fprintf (stderr, "%s: problems in NLM command language input:\n",
  888.            program_name);
  889.       done = 1;
  890.     }
  891. }
  892.  
  893. /* Issue a warning.  */
  894.  
  895. static void
  896. nlmheader_warn (s, imax)
  897.      const char *s;
  898.      int imax;
  899. {
  900.   nlmheader_identify ();
  901.   fprintf (stderr, "%s:%d: %s", current.name, current.lineno, s);
  902.   if (imax != -1)
  903.     fprintf (stderr, " (max %d)", imax);
  904.   fprintf (stderr, "\n");
  905. }
  906.  
  907. /* Report an error.  */
  908.  
  909. static void
  910. nlmheader_error (s)
  911.      const char *s;
  912. {
  913.   nlmheader_warn (s, -1);
  914.   ++parse_errors;
  915. }
  916.  
  917. /* Add a string to a string list.  */
  918.  
  919. static struct string_list *
  920. string_list_cons (s, l)
  921.      char *s;
  922.      struct string_list *l;
  923. {
  924.   struct string_list *ret;
  925.  
  926.   ret = (struct string_list *) xmalloc (sizeof (struct string_list));
  927.   ret->next = l;
  928.   ret->string = s;
  929.   return ret;
  930. }
  931.  
  932. /* Append a string list to another string list.  */
  933.  
  934. static struct string_list *
  935. string_list_append (l1, l2)
  936.      struct string_list *l1;
  937.      struct string_list *l2;
  938. {
  939.   register struct string_list **pp;
  940.  
  941.   for (pp = &l1; *pp != NULL; pp = &(*pp)->next)
  942.     ;
  943.   *pp = l2;
  944.   return l1;
  945. }
  946.  
  947. /* Append a string to a string list.  */
  948.  
  949. static struct string_list *
  950. string_list_append1 (l, s)
  951.      struct string_list *l;
  952.      char *s;
  953. {
  954.   struct string_list *n;
  955.   register struct string_list **pp;
  956.  
  957.   n = (struct string_list *) xmalloc (sizeof (struct string_list));
  958.   n->next = NULL;
  959.   n->string = s;
  960.   for (pp = &l; *pp != NULL; pp = &(*pp)->next)
  961.     ;
  962.   *pp = n;
  963.   return l;
  964. }
  965.  
  966. /* Duplicate a string in memory.  */
  967.  
  968. static char *
  969. xstrdup (s)
  970.      const char *s;
  971. {
  972.   unsigned long len;
  973.   char *ret;
  974.  
  975.   len = strlen (s);
  976.   ret = xmalloc (len + 1);
  977.   strcpy (ret, s);
  978.   return ret;
  979. }
  980.